#include "j8ftp.h"

LRESULT CALLBACK CompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) {
  char c[2][FILE_SIZE];
  ListView_GetItemText(hLister, lParam1, 1, c[0], sizeof(c[0]));
  ListView_GetItemText(hLister, lParam2, 1, c[1], sizeof(c[1]));

  return strcmp(c[1], c[0]);
}

LRESULT CALLBACK ConnectProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
  switch(message) {
  case WM_COMMAND:
    return loger(hWnd, LOWORD(wParam));
  default:
    return FALSE;
  }
}

void alert(char *content) {
  MessageBox(NULL, content, INTERNAL_NAME, MB_OK);
}

void alerts(char *content, ...) {
  char *c, d[BUFFER_SIZE] = {0};
  strcpy(d, content);

  va_list vl;
  va_start(vl, content);
  while(c = va_arg(vl, char *)) {
    strcat(d, c);
  }
  va_end(vl);

  alert(d);
}

void clear(void *ptr) {
  if(ptr) {
    free(ptr);
    ptr = NULL;
  }
}

void clipClient(char *path) {
  char c[BUFFER_SIZE] = {0}, *d = cuter(path);
  strcpy(j8ftpPathC, path);
  if(strcmp(path, "")) {
    if(GetFileAttributes(joinLast(c, path, "\\", d, NULL)) & FILE_ATTRIBUTE_DIRECTORY) {
      digClient(d);
    } else {
      if(strlen(j8ftpFiles)) {
        toExpand("", d);
        joinLast(j8ftpFiles, "\r\n", d, NULL);
      } else {
        strcpy(j8ftpFiles, d);
      }
    }
  }
}

void clipServer() {
  char c[MAX_PATH], d[FILE_SIZE];
  int i = -1;

  memset(j8ftpDirectorys, 0, sizeof(j8ftpDirectorys));
  memset(j8ftpFiles, 0, _msize(j8ftpFiles));
  memset(j8ftpPathS, 0, sizeof(j8ftpPathS));
  joinLast(j8ftpPathS, pwd(j8ftpSocket), "/", NULL);

  while((i = ListView_GetNextItem(hLister, i, LVNI_SELECTED)) > -1) {
    ListView_GetItemText(hLister, i, 0, c, sizeof(c));
    ListView_GetItemText(hLister, i, 1, d, sizeof(d));
    if(strcmp(d, j8ftpDir)) {
      if(strlen(j8ftpFiles)) {
        toExpand("", c);
        joinLast(j8ftpFiles, "\r\n", c, NULL);
      } else {
        strcpy(j8ftpFiles, c);
      }
    } else {
      digServer(c);
    }
  }
}

char *cuter(char *path) {
  path += strlen(path) - 1;

  while(*path) {
    if(*path == '\\') {
      *path = '\0';
      break;
    } else {
      path--;
    }
  }

  return ++path;
}

void digClient(char *path) {
  char c[MAX_PATH] = {0};

  if(strlen(j8ftpDirectorys[1])) {
    joinLast(j8ftpDirectorys[1], "\r\n", path, NULL);
  } else {
    strcpy(j8ftpDirectorys[1], path);
  }

  WIN32_FIND_DATA wfd;
  HANDLE hFinder = FindFirstFile(joinLast(c, j8ftpPathC, "\\", path, "\\*.*", NULL), &wfd);
  do {
    if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
      if(strcmp(wfd.cFileName, ".") && strcmp(wfd.cFileName, "..")) {
        memset(c, 0, sizeof(c));
        digClient(joinLast(c, path, "\\", wfd.cFileName, NULL));
      }
    } else {
      toExpand(path, wfd.cFileName);
      if(strlen(j8ftpFiles)) {
        joinLast(j8ftpFiles, "\r\n", path, "\\", wfd.cFileName, NULL);
      } else {
        joinLast(j8ftpFiles, path, "\\", wfd.cFileName, NULL);
      }
    }
  } while(FindNextFile(hFinder, &wfd));
  FindClose(hFinder);
}

void digServer(char *path) {
  char *c, d[MAX_PATH], *e[MAX_PATH];
  int i;

  if(strlen(j8ftpDirectorys[0])) {
    joinFirst(j8ftpDirectorys[0], path, "\r\n", NULL);
  } else {
    strcpy(j8ftpDirectorys[0], path);
  }

  if(strlen(j8ftpDirectorys[1])) {
    joinLast(j8ftpDirectorys[1], "\r\n", path, NULL);
  } else {
    strcpy(j8ftpDirectorys[1], path);
  }

  ls(j8ftpSocket, path, &c, &i);
  memset(e, 0, sizeof(e));
  spliter(c, "\r\n", e, &i);

  while(i--) {
    sscanf(e[i], "%*10s %*1d %*s %*s %*d %*3s %*[0-9] %*[0-9:] %[^\n]", d);
    if(e[i][0] == 'd') {
      digServer(joinFirst(d, path, "/", NULL));
    } else {
      toExpand(path, d);
      if(strlen(j8ftpFiles)) {
        joinLast(j8ftpFiles, "\r\n", path, "/", d, NULL);
      } else {
        joinLast(j8ftpFiles, path, "/", d, NULL);
      }
    }
  }
}

int freeAll(size_t n) {
  clear(j8ftpFiles);

  while(n--) {
    clear(j8ftpStrings[n]);
  }

  return n;
}

char *joinFirst(char *src, ...) {
  char *c, d[BUFFER_MAX] = {0};

  va_list vl;
  va_start(vl, src);
  while(c = va_arg(vl, char *)) {
    strcat(d, c);
  }
  va_end(vl);

  strcat(d, src);
  return strcpy(src, d);
}

char *joinLast(char *src, ...) {
  char *c, d[BUFFER_MAX] = {0};
  strcpy(d, src);

  va_list vl;
  va_start(vl, src);
  while(c = va_arg(vl, char *)) {
    strcat(d, c);
  }
  va_end(vl);

  return strcpy(src, d);
}

char *loader(double id) {
  char *c = (char *)calloc(0xFF, sizeof(char));
  double di, d = modf(id, &di);
  LoadString(GetModuleHandle(NULL), di, c, _msize(c));
  static int i;
  clear(j8ftpStrings[i % 4]);
  j8ftpStrings[(i++) % 4] = c;
  return c + (int)floor(d * 1000);
}

BOOL loger(HWND hWnd, WORD wId) {
  switch(wId) {
  case IDD_DIALOG_OK:
    GetWindowText(GetDlgItem(hDialog, IDD_DIALOG_ACCOUNT), j8ftpAccount, sizeof(j8ftpAccount));
    GetWindowText(GetDlgItem(hDialog, IDD_DIALOG_PASSWORD), j8ftpPassword, sizeof(j8ftpPassword));
    GetWindowText(GetDlgItem(hDialog, IDD_DIALOG_IP), j8ftpIP, sizeof(j8ftpIP));
    GetWindowText(GetDlgItem(hDialog, IDD_DIALOG_PORT), j8ftpPort, sizeof(j8ftpPort));
    ShowWindow(hDialog, SW_HIDE);
    if(toConnect()) {
      toListen();
    } else {
      ShowWindow(hDialog, SW_SHOW);
    }
    break;
  case IDCANCEL:
    EndDialog(hWnd, wId);
    return TRUE;
  case IDOK:
    SendMessage(hDialog, WM_COMMAND, IDD_DIALOG_OK, 0);
    return TRUE;
  default:
    return FALSE;
  }
}

void partof(void (*f)(int, char *), int order, char *str) {
  char *c = strtok(str, "\r\n");
  while(c) {
    (*f)(order, c);
    c = strtok(NULL, "\r\n");
  }
}

void spliter(char *src, const char *delim, char **dest, int *n) {
  int i = 0;

  char *c = strtok(src, delim);
  while(c) {
    *dest++ = c;
    i++;
    c = strtok(NULL, delim);
  }

  *n = i;
}

char *startsWith(char *src, const char *keyword) {
  int i = strlen(keyword);
  if(strncmp(src, keyword, i)) {
    return NULL;
  } else {
    return src + i;
  }
}

void toChangeDirectory(int index) {
  char c[BUFFER_SIZE], d[FILE_SIZE];
  switch(index) {
  case -1:
    strcpy(c, pwd(j8ftpSocket));
    index = strlen(c);
    while(index--) {
      if(*(c + index) == '/') {
        c[index + 1] = '\0';
        break;
      }
    }
    strcpy(d, j8ftpDir);
    break;
  case -2:
    strcpy(c, "/");
    strcpy(d, j8ftpDir);
    break;
  default:
    ListView_GetItemText(hLister, index, 0, c, sizeof(c));
    ListView_GetItemText(hLister, index, 1, d, sizeof(d));
  }

  if(ListView_GetSelectedCount(hLister) > 1 || strcmp(d, j8ftpDir)) {
    toDownload();
  } else {
    cd(j8ftpSocket, c);
    toListen();
  }
}

void toChangeWindow() {
  RECT r;
  long l = GetWindowLong(hFrame, GWL_EXSTYLE);
  GetWindowRect(hFrame, &r);
  HMENU hMenu = GetMenu(hFrame);
  if (l & WS_EX_TOPMOST) {
    SetWindowPos(hFrame, HWND_NOTOPMOST, r.left, r.top, r.right, r.bottom, SWP_NOSIZE);
    SetWindowLong(hFrame, GWL_EXSTYLE, l &~ WS_EX_LAYERED);
    SetLayeredWindowAttributes(hFrame, 0, 255, LWA_ALPHA);
    CheckMenuItem(hMenu, 223, MF_BYCOMMAND | MF_UNCHECKED);
  } else {
    SetWindowPos(hFrame, HWND_TOPMOST, r.left, r.top, r.right, r.bottom, SWP_NOSIZE);
    SetWindowLong(hFrame, GWL_EXSTYLE, l | WS_EX_LAYERED);
    SetLayeredWindowAttributes(hFrame, 0, 180, LWA_ALPHA);
    CheckMenuItem(hMenu, 223, MF_BYCOMMAND | MF_CHECKED);
  }
}

void toClickNotifyIconData(HWND hWnd, LPARAM lParam) {
  POINT pt;
  GetCursorPos(&pt);
  HMENU hMenu = GetSubMenu(GetMenu(hFrame), 0);
  switch(lParam) {
  case WM_LBUTTONDOWN:
    toSetNotifyIconData();
    break;
  case WM_RBUTTONDOWN:
    SetForegroundWindow(hWnd);
    TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, pt.x, pt.y, 0, hWnd, NULL);
    toSetNotifyIconData();
    break;
  }
}

BOOL toConnect() {
  j8ftpSocket = login(j8ftpAccount, j8ftpPassword, j8ftpIP, atoi(j8ftpPort));
  if(j8ftpSocket == INVALID_SOCKET) {
    return FALSE;
  } else {
    return TRUE;
  }
}

void toCreateDialog(HWND hParent) {
  hDialog = CreateDialog(
              (HINSTANCE)GetWindowLongPtr(hParent, GWLP_HINSTANCE),
              MAKEINTRESOURCE(IDD_DIALOG_CONNECT),
              hParent,
              (DLGPROC)ConnectProc
            );

  SetWindowText(GetDlgItem(hDialog, IDD_DIALOG_IP), j8ftpIP);
  SetWindowText(GetDlgItem(hDialog, IDD_DIALOG_ACCOUNT), j8ftpAccount);
  SetWindowText(GetDlgItem(hDialog, IDD_DIALOG_PORT), j8ftpPort);
}

void toCreateFrame(HINSTANCE hInstance) {
  WNDCLASS wc;
  wc.style = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc = WinProc;
  wc.cbClsExtra = 0;
  wc.cbWndExtra = 0;
  wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
  wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  wc.hIcon = hIcon;
  wc.hInstance = hInstance;
  wc.lpszClassName = INTERNAL_NAME;
  wc.lpszMenuName = MAKEINTRESOURCE(200);
  RegisterClass(&wc);

  int frameHeight = 360,
      frameWidth = 600,
      screenHeight = GetSystemMetrics(SM_CYSCREEN),
      screenWidth  = GetSystemMetrics(SM_CXSCREEN);

  hFrame = CreateWindowEx(
             WS_EX_ACCEPTFILES | WS_EX_CONTROLPARENT,
             INTERNAL_NAME,
             NULL,
             WS_CAPTION | WS_SYSMENU,
             (screenWidth - frameWidth) / 2,
             (screenHeight - frameHeight) / 2,
             frameWidth,
             frameHeight,
             NULL,
             NULL,
             hInstance,
             NULL
           );

  SetWindowText(hFrame, PROGRAM_INFO);
  ShowWindow(hFrame, SW_SHOW);
  UpdateWindow(hFrame);
}

void toCreateLister(HWND hParent) {
  RECT r;
  GetClientRect(hParent, &r);

  hLister = CreateWindow(
              "SysListView32",
              "",
              WS_CHILD | WS_VISIBLE |
              LVS_EDITLABELS | LVS_NOSORTHEADER | LVS_REPORT | LVS_SHOWSELALWAYS,
              r.left,
              r.top,
              r.right,
              r.bottom,
              hParent,
              NULL,
              (HINSTANCE)GetWindowLongPtr(hParent, GWLP_HINSTANCE),
              NULL
            );

  LV_COLUMN lvColumn;
  lvColumn.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
  lvColumn.cx = r.right - r.left - 210;
  lvColumn.iSubItem = 0;
  lvColumn.pszText = TEXT(loader(IDS_LIST_NAME));
  ListView_InsertColumn(hLister, 0, &lvColumn);
  lvColumn.cx = 90;
  lvColumn.iSubItem = 1;
  lvColumn.pszText = TEXT(loader(IDS_LIST_SIZE));
  ListView_InsertColumn(hLister, 1, &lvColumn);
  lvColumn.cx = 100;
  lvColumn.iSubItem = 2;
  lvColumn.pszText = TEXT(loader(IDS_LIST_DATETIME));
  ListView_InsertColumn(hLister, 2, &lvColumn);
}

void toCreateNotifyIconData(HWND hWnd) {
  nid.cbSize = sizeof(nid);
  nid.hIcon = hIcon;
  nid.hWnd = hWnd;
  nid.uCallbackMessage = WM_TASKBAR_TRAY;
  nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
  nid.uID = 20190813;
}

void toDelete() {
  clipServer();
  partof(toDoit, FTP_SERVER_DELETE_FILE, j8ftpFiles);
  partof(toDoit, FTP_SERVER_DELETE_DIRECTORY, j8ftpDirectorys[0]);
  toListen();
}

void toDoit(int order, char *str) {
  switch(order) {
  case FTP_CLIENT_MAKE_DIRECTORY:
    memset(j8ftpBuffer, 0, sizeof(j8ftpBuffer));
    mkdir(joinLast(j8ftpBuffer, j8ftpPathS, "\\", str, NULL));
    break;
  case FTP_DOWNLOAD:
    memset(j8ftpBuffer, 0, sizeof(j8ftpBuffer));
    dl(j8ftpSocket, str, joinLast(j8ftpBuffer, j8ftpPathS, "\\", str, NULL), 0);
    break;
  case FTP_SERVER_DELETE_DIRECTORY:
    dd(j8ftpSocket, str);
    break;
  case FTP_SERVER_DELETE_FILE:
    df(j8ftpSocket, str);
    break;
  case FTP_SERVER_DELETE_PATH:
    memset(j8ftpBuffer, 0, sizeof(j8ftpBuffer));
    dd(j8ftpSocket, joinLast(j8ftpBuffer, j8ftpPathS, str, NULL));
    break;
  case FTP_SERVER_MAKE_DIRECTORY:
    md(j8ftpSocket, str);
    break;
  case FTP_SERVER_MOVE_FILE:
    memset(j8ftpBuffer, 0, sizeof(j8ftpBuffer));
    rm(j8ftpSocket, joinLast(j8ftpBuffer, j8ftpPathS, str, NULL), str);
    break;
  case FTP_UPLOAD:
    memset(j8ftpBuffer, 0, sizeof(j8ftpBuffer));
    ul(j8ftpSocket, joinLast(j8ftpBuffer, j8ftpPathC, "\\", str, NULL), str, NULL);
    break;
  }
}

void toDownload() {
  clipServer();

  BROWSEINFO bi = {0};
  bi.hwndOwner = hFrame;
  bi.lpszTitle = loader(IDS_FTP_DOWNLOAD);
  bi.pszDisplayName = j8ftpPathS;
  bi.ulFlags = BIF_NEWDIALOGSTYLE;
  LPITEMIDLIST lpiil = SHBrowseForFolder(&bi);
  if(SHGetPathFromIDList(lpiil, j8ftpPathS)) {
    partof(toDoit, FTP_CLIENT_MAKE_DIRECTORY, j8ftpDirectorys[1]);
    partof(toDoit, FTP_DOWNLOAD, j8ftpFiles);
  }
}

void toDropFiles(HWND hWnd, HDROP hDropInfo) {
  memset(j8ftpDirectorys, 0, sizeof(j8ftpDirectorys));
  memset(j8ftpFiles, 0, _msize(j8ftpFiles));

  int i = DragQueryFile(hDropInfo, -1, NULL, 0);
  while(i--) {
    DragQueryFile(hDropInfo, i, j8ftpBuffer, sizeof(j8ftpBuffer));
    clipClient(j8ftpBuffer);
  }
  DragFinish(hDropInfo);
  toUpload(FALSE);
}

void toEditLabel() {
  int i = ListView_GetSelectionMark(hLister);
  ListView_GetItemText(hLister, i, 0, j8ftpBuffer, sizeof(j8ftpBuffer));
  hEditor = ListView_GetEditControl(hLister);
}

void toExecuteL(LPARAM lParam) {
  LPNMITEMACTIVATE lia = (LPNMITEMACTIVATE)lParam;
  switch(lia->hdr.code) {
  case LVN_BEGINLABELEDIT:
    toEditLabel();
    break;
  case LVN_ENDLABELEDIT:
    toRename();
    break;
  case NM_DBLCLK:
  case NM_RETURN:
    toChangeDirectory(ListView_GetSelectionMark(hLister));
    break;
  }
}

void toExecuteW(HWND hWnd, WPARAM wParam) {
  switch(LOWORD(wParam)) {
  case 201:
  case 301:
    toUpload(TRUE);
    break;
  case 202:
  case 302:
    toDownload();
    break;
  case 203:
  case 303:
    toInsert(loader(IDS_FILE_NEW), j8ftpDir, j8ftpNow);
    SetFocus(hLister);
    ListView_EditLabel(hLister, 0);
    break;
  case 204:
  case 304:
    ListView_EditLabel(hLister, ListView_GetSelectionMark(hLister));;
    break;
  case 211:
    toChangeDirectory(ListView_GetSelectionMark(hLister));
    break;
  case 212:
  case 312:
    toChangeDirectory(-1);
    break;
  case 213:
  case 313:
    clipServer();
    break;
  case 214:
  case 314:
    toPaste();
    break;
  case 216:
  case 316:
    toDelete();
    break;
  case 217:
  case 317:
    toListen();
    break;
  case 221:
  case 321:
    toShowDialog();
    break;
  case 222:
  case 322:
    toChangeDirectory(-2);
    break;
  case 223:
  case 323:
    toChangeWindow();
    break;
  case 224:
  case 324:
    ShowWindow(hWnd, SW_MINIMIZE);
    break;
  case 230:
    alert("https://gitee.com/bi547552596/j8ftp");
    break;
  case 239:
  case 339:
    xSeal(hWnd, 25, 2);
    break;
  case 299:
  case 397:
  case 399:
    PostMessage(hWnd, WM_CLOSE, 0, 0);
    break;
  }
}

void toExpand(char *path, char *name) {
  if(strlen(j8ftpFiles) + strlen(path) + strlen(name) + 4 > _msize(j8ftpFiles)) {
    char *c = (char *)calloc(_msize(j8ftpFiles) + 1024, sizeof(char));
    strcpy(c, j8ftpFiles);
    clear(j8ftpFiles);
    j8ftpFiles = c;
  }
}

void toInsert(char *filename, char *size, char *datetime) {
  LV_ITEM lvItem;
  lvItem.mask = LVIF_TEXT;
  lvItem.cchTextMax = MAX_PATH;
  lvItem.iItem = 0;
  lvItem.iSubItem = 0;
  lvItem.pszText = filename;
  ListView_InsertItem(hLister, &lvItem);
  lvItem.iSubItem = 1;
  lvItem.pszText = size;
  ListView_SetItem(hLister, &lvItem);
  lvItem.iSubItem = 2;
  lvItem.pszText = datetime;
  ListView_SetItem(hLister, &lvItem);
}

void toListen() {
  ListView_DeleteAllItems(hLister);
  char *c, datetime[FILE_DATETIME], size[FILE_SIZE];
  int i;

  ls(j8ftpSocket, "", &c, &i);
  c = strtok(c, "\r\n");
  while(c) {
    sscanf(
      c,
      "%*10s %*1d %*s %*s %d %3s %[0-9] %[0-9:] %[^\n]",
      &i,
      datetime,
      datetime + 4,
      datetime + 7,
      j8ftpBuffer
    );
    datetime[3] = datetime[6] = ' ';
    if(c[0] == 'd') {
      strcpy(size, j8ftpDir);
    } else {
      char f[8] = "%.2f \0";
      const char nb[][3] = {"B\0", "KB\0", "MB\0", "GB\0", "TB\0"};
      double d = i;
      for(i = 0; i < sizeof(nb[0]) / sizeof(nb[0][0]); i++) {
        if(d >= 1024) {
          d /= 1024;
        } else {
          sprintf(size, strcat(f, nb[i]), d);
          break;
        }
      }
    }
    toInsert(j8ftpBuffer, size, datetime);
    c = strtok(NULL, "\r\n");
  }

  SetFocus(hLister);
  ListView_SortItemsEx(hLister, CompareProc, (LPARAM)hLister);
  ListView_SetItemState(hLister, 0, LVIS_SELECTED, LVIS_SELECTED);
}

void toPaste() {
  partof(toDoit, FTP_SERVER_MAKE_DIRECTORY, j8ftpDirectorys[1]);
  partof(toDoit, FTP_SERVER_MOVE_FILE, j8ftpFiles);
  partof(toDoit, FTP_SERVER_DELETE_PATH, j8ftpDirectorys[0]);
  toListen();
}

void toRecoverNotifyIconData(UINT message) {
  if(message == WM_TASKBAR_CREATED) {
    toSetNotifyIconData();
  }
}

void toRename() {
  char c[MAX_PATH], d[FILE_DATETIME];
  GetWindowText(hEditor, c, sizeof(c));
  ListView_GetItemText(hLister, ListView_GetSelectionMark(hLister), 2, d, sizeof(d));
  if(strcmp(d, j8ftpNow)) {
    if(strcmp(c, j8ftpBuffer)) {
      if(rm(j8ftpSocket, j8ftpBuffer, c)) {
        alerts("\"", j8ftpBuffer, "\" ", loader(IDS_FILE_RENAME_FAIL), NULL);
      } else {
        alerts("\"", j8ftpBuffer, "\" ", loader(IDS_FILE_RENAME_SUCCESS), NULL);
      }
    }
  } else {
    if(md(j8ftpSocket, c)) {
      alert(loader(IDS_FILE_NEW_FAIL));
    } else {
      alert(loader(IDS_FILE_NEW_SUCCESS));
    }
  }

  toListen();
}

void toSetNotifyIconData() {
  if(IsWindowVisible(hFrame)) {
    GetWindowText(hFrame, nid.szTip, sizeof(nid.szTip));
    Shell_NotifyIcon(NIM_ADD, &nid);
    ShowWindow(hFrame, SW_HIDE);
  } else {
    ShowWindow(hFrame, SW_SHOWNORMAL);
    Shell_NotifyIcon(NIM_DELETE, &nid);
  }
}

void toShowDialog() {
  if(pasv(j8ftpSocket) == SOCKET_ERROR) {
    RECT rd, rf;
    GetWindowRect(hFrame, &rf);
    GetWindowRect(hDialog, &rd);

    MoveWindow(
      hDialog,
      rf.left + (rf.right - rf.left - rd.right + rd.left) / 2,
      rf.top + (rf.bottom - rf.top - rd.bottom + rd.top) / 2,
      rd.right - rd.left,
      rd.bottom - rd.top,
      TRUE
    );

    ShowWindow(hDialog, SW_SHOW);
  } else {
    toListen();
  }
}

void toShowPopupMenu(HWND hWnd) {
  POINT p;
  GetCursorPos(&p);
  HMENU hMenu = GetSubMenu(GetMenu(hFrame), 1);
  TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, p.x, p.y, 0, hWnd, NULL);
}

BOOL toSplitCmdLine(LPSTR sCmdLine, int iSize) {
  if(!strlen(sCmdLine)) {
    return iSize;
  }

  LPWSTR *lpws = CommandLineToArgvW(GetCommandLineW(), &iSize);
  while(iSize) {
    WideCharToMultiByte(CP_ACP, 0, lpws[iSize--], -1, j8ftpBuffer, sizeof(j8ftpBuffer), NULL, NULL);
    if(j8ftpBuffer[0] == '-') {
      char *c = startsWith(j8ftpBuffer, "-account:");
      if(c) {
        strcpy(j8ftpAccount, c);
        continue;
      }
      c = startsWith(j8ftpBuffer, "-ip:");
      if(c) {
        strcpy(j8ftpIP, c);
        continue;
      }
      c = startsWith(j8ftpBuffer, "-password:");
      if(c) {
        strcpy(j8ftpPassword, c);
        continue;
      }
      c = startsWith(j8ftpBuffer, "-port:");
      if(c) {
        strcpy(j8ftpPort, c);
        continue;
      }
      c = startsWith(j8ftpBuffer, "-wd:");
      if(c) {
        strcpy(j8ftpPathS, c);
        continue;
      }
    } else {
      clipClient(j8ftpBuffer);
    }
  }
  LocalFree(lpws);

  return toConnect();
}

void toUpload(int isOpenFileDialog) {
  if(isOpenFileDialog) {
    OPENFILENAME ofn = {0};
    ofn.Flags = OFN_ALLOWMULTISELECT | OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
    ofn.hwndOwner = hFrame;
    ofn.lpstrDefExt = "";
    ofn.lpstrFile = j8ftpBuffer;
    ofn.lpstrFilter = NULL;
    ofn.lpstrInitialDir = "";
    ofn.lpstrTitle = loader(IDS_FTP_UPLOAD);
    ofn.lStructSize = sizeof(ofn);
    ofn.nMaxFile = sizeof(j8ftpBuffer);

    memset(j8ftpDirectorys, 0, sizeof(j8ftpDirectorys));
    if(GetOpenFileName(&ofn)) {
      strncpy(j8ftpPathC, j8ftpBuffer, ofn.nFileOffset);
      j8ftpPathC[ofn.nFileOffset] = '\0';
      if(j8ftpPathC[strlen(j8ftpPathC) - 1] != '\\') {
        strcat(j8ftpPathC, "\\");
      }

      char *c = j8ftpBuffer + ofn.nFileOffset;
      memset(j8ftpFiles, 0, _msize(j8ftpFiles));
      while(*c) {
        ul(j8ftpSocket, strcat(j8ftpPathC, c), c, &isOpenFileDialog);
        c += strlen(c) + 1;
      }
    }
  } else {
    if(strlen(j8ftpDirectorys[1])) {
      partof(toDoit, FTP_SERVER_MAKE_DIRECTORY, j8ftpDirectorys[1]);
    }
    partof(toDoit, FTP_UPLOAD, j8ftpFiles);
  }

  toListen();
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR sCmdLine, int iCmdShow) {
  j8ftpFiles = (char *)calloc(BUFFER_MAX, sizeof(char));

  if(toSplitCmdLine(sCmdLine, 0)) {
    if(strlen(j8ftpPathS)) {
      cd(j8ftpSocket, j8ftpPathS);
    }

    if(strlen(j8ftpFiles)) {
      toUpload(FALSE);
      logout(j8ftpSocket);
      return -1;
    }
  }

  hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MAINFRAME));
  toCreateFrame(hInstance);
  toShowDialog();

  MSG msg;
  ZeroMemory(&msg, sizeof(msg));
  HACCEL hAccel = LoadAccelerators(hInstance, MAKEINTRESOURCE(300));

  while(GetMessage(&msg, NULL, 0, 0)) {
    if(!IsDialogMessage(hDialog, &msg)) {
      if(!TranslateAccelerator(hFrame, hAccel, &msg)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
      }
    }
  }

  UnregisterClass(INTERNAL_NAME, hInstance);
  logout(j8ftpSocket);
  return freeAll(4);
}

LRESULT CALLBACK WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
  switch(message) {
  case WM_CLOSE:
    DestroyWindow(hWnd);
    break;
  case WM_COMMAND:
    toExecuteW(hWnd, wParam);
    break;
  case WM_CONTEXTMENU:
    toShowPopupMenu(hWnd);
    break;
  case WM_CREATE:
    toCreateDialog(hWnd);
    toCreateLister(hWnd);
    toCreateNotifyIconData(hWnd);
    break;
  case WM_DESTROY:
    PostQuitMessage(0);
    break;
  case WM_DROPFILES:
    toDropFiles(hWnd, (HDROP)wParam);
    break;
  case WM_NOTIFY:
    if(wParam == GetDlgCtrlID(hLister)) {
      toExecuteL(lParam);
      SendMessage(hLister, WM_NOTIFY, wParam, lParam);
    }
    break;
  case WM_SIZE:
    if(wParam == SIZE_MINIMIZED) {
      toSetNotifyIconData();
    }
    break;
  case WM_TASKBAR_TRAY:
    toClickNotifyIconData(hWnd, lParam);
    break;
  default:
    toRecoverNotifyIconData(message);
    return DefWindowProc(hWnd, message, wParam, lParam);
  }
}